package com.micangcaihang.common.widget;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Path;
import android.graphics.RectF;
import android.graphics.drawable.GradientDrawable;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.widget.FrameLayout;

import com.micangcaihang.common.R;


/**
 * 作者：Fandy on 2017/7/23 21:29
 * 邮箱：fandy618@hotmail.com
 */

public class RoundedCornerFrameLayout extends FrameLayout {

    private int mWidth;
    private int mHeight;
    private float mCornerRadius = 4.f;
    private int mStrokeWidth = 0;
    private int mStrokeColor;
    private int mFillColor;

    private boolean mRoundTopLeft = true;
    private boolean mRoundTopRight = true;
    private boolean mRoundBottomRight = true;
    private boolean mRoundBottomLeft = true;

    private Path mClipPath = new Path();

    public RoundedCornerFrameLayout(Context context, AttributeSet attributeSet) {
        super(context, attributeSet);
        TypedArray attributes = context.obtainStyledAttributes(attributeSet,
                R.styleable.RoundedCornerFrameLayout);

        mWidth = getWidth();
        mHeight = getHeight();

        mRoundTopLeft = attributes.getBoolean(
                R.styleable.RoundedCornerFrameLayout_round_top_left, true);
        mRoundTopRight = attributes.getBoolean(
                R.styleable.RoundedCornerFrameLayout_round_top_right, true);
        mRoundBottomRight = attributes.getBoolean(
                R.styleable.RoundedCornerFrameLayout_round_bottom_right, true);
        mRoundBottomLeft = attributes.getBoolean(
                R.styleable.RoundedCornerFrameLayout_round_bottom_left, true);
        mCornerRadius = attributes.getDimension(R.styleable.RoundedCornerFrameLayout_corner_radius,
                TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 4,
                        context.getResources().getDisplayMetrics()));
        mStrokeWidth = (int)attributes.getDimension(
                R.styleable.RoundedCornerFrameLayout_stroke_width, 0f);
        mStrokeColor = attributes.getColor(R.styleable.RoundedCornerFrameLayout_stroke_color,
                getResources().getColor(android.R.color.transparent));
        mFillColor = attributes.getColor(R.styleable.RoundedCornerFrameLayout_fill_color,
                getResources().getColor(android.R.color.transparent));
        attributes.recycle();

        rebuildBackgroundShape();
        rebuildClipPath();
    }

    /**
     * Setter for rounding top left corner
     * @param shouldRound a boolean indicating whether the top left corner should be rounded
     */
    public void setRoundTopLeft(boolean shouldRound) {
        mRoundTopLeft = shouldRound;
        rebuildBackgroundShape();
        rebuildClipPath();
    }

    /**
     * Setter for rounding top right corner
     * @param shouldRound a boolean indicating whether the top right corner should be rounded
     */
    public void setRoundTopRight(boolean shouldRound) {
        mRoundTopRight = shouldRound;
        rebuildBackgroundShape();
        rebuildClipPath();
    }

    /**
     * Setter for rounding bottom right corner
     * @param shouldRound a boolean indicating whether the bottom right corner should be rounded
     */
    public void setRoundBottomRight(boolean shouldRound) {
        mRoundBottomRight = shouldRound;
        rebuildBackgroundShape();
        rebuildClipPath();
    }

    /**
     * Setter for rounding bottom left corner
     * @param shouldRound a boolean indicating whether the bottom left corner should be rounded
     */
    public void setRoundBottomLeft(boolean shouldRound) {
        mRoundBottomLeft = shouldRound;
        rebuildBackgroundShape();
        rebuildClipPath();
    }

    /**
     * Getter for list of corner radii
     * @return a list of values indicating the inner and outer radius of each corner
     */
    private float[] getCornerRadii() {
        return new float[] {
                (mRoundTopLeft ? mCornerRadius : 0),
                (mRoundTopLeft ? mCornerRadius : 0),
                (mRoundTopRight ? mCornerRadius : 0),
                (mRoundTopRight ? mCornerRadius : 0),
                (mRoundBottomRight ? mCornerRadius : 0),
                (mRoundBottomRight ? mCornerRadius : 0),
                (mRoundBottomLeft ? mCornerRadius : 0),
                (mRoundBottomLeft ? mCornerRadius : 0)
        };
    }

    @Override
    protected void onSizeChanged(int width, int height, int oldw, int oldh) {
        // If the size changes, restore the clip path
        super.onSizeChanged(width, height, oldw, oldh);
        mWidth = width;
        mHeight = height;
        rebuildClipPath();
    }

    @Override
    protected void dispatchDraw(Canvas canvas) {
        // Draw as normal and clip to the clip path
        int save = canvas.save();
        canvas.clipPath(mClipPath);
        super.dispatchDraw(canvas);
        canvas.restoreToCount(save);
    }

    /**
     * Rebuild the clip path based on config properties
     */
    private void rebuildClipPath() {
        RectF rect = new RectF(
                mStrokeWidth,
                mStrokeWidth,
                mWidth - mStrokeWidth,
                mHeight - mStrokeWidth);
        mClipPath.reset();
        mClipPath.addRoundRect(rect, getCornerRadii(), Path.Direction.CW);
    }

    /**
     * Rebuild the background shape based on config properties
     */
    private void rebuildBackgroundShape() {
        GradientDrawable shape = new GradientDrawable();
        shape.setShape(GradientDrawable.RECTANGLE);
        shape.setCornerRadii(getCornerRadii());
        shape.setColor(mFillColor);
        shape.setStroke(mStrokeWidth, mStrokeColor);
        setBackgroundDrawable(shape);
    }

    /**
     * Setter for the config properties of the background shape and clip path
     * @param cornerRadius The radius of the rounded corners
     * @param strokeWidth The width of the outer stroke of the background shape
     * @param strokeColor The color of the outer stroke of the background shape
     * @param fillColor The fill color of the background shape
     */
    public void setBackgroundDetails(Float cornerRadius,
                                     Integer strokeWidth,
                                     Integer strokeColor,
                                     Integer fillColor) {
        if (cornerRadius != null) {
            mCornerRadius = cornerRadius;
        }

        if (strokeWidth != null) {
            mStrokeWidth = strokeWidth;
        }

        if (strokeColor != null) {
            mStrokeColor = strokeColor;
        }

        if (fillColor != null) {
            mFillColor = fillColor;
        }

        rebuildBackgroundShape();
        rebuildClipPath();
    }
}
